﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HZY.AdminCodeGeneration.Models;
using HZY.AdminCodeGeneration.Razor;
using HZY.AdminCodeGeneration.Repository;
using HZY.AdminCodeGeneration.Utility;
using HZY.AdminCodeGeneration.Utility.ScanDIService.Interface;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using NPOI.HSSF.UserModel;

namespace HZY.AdminCodeGeneration.Services
{
    /// <summary>
    /// 代码生成 服务
    /// </summary>
    public class HzyAdminSpaService : IDITransientSelf
    {
        private readonly string _webRootPath;
        private const string TemplateRootPath = "/wwwroot/template/hzy_admin_spa";
        private const string CodesRootPath = "/template/hzy_admin_spa/codes";
        private const string ZipRootPath = "/template/hzy_admin_spa/zip";
        private static List<AppTableInfo> _appTableInfos;
        private readonly IRazorViewRender _razorViewRender;
        private readonly AppTableInfoRepository _appTableInfoRepository;
        private readonly string Namespace;

        public HzyAdminSpaService(IRazorViewRender razorViewRender,
            IWebHostEnvironment webHostEnvironment,
            IConfiguration configuration, AppTableInfoRepository appTableInfoRepository)
        {
            _razorViewRender = razorViewRender;
            this._webRootPath = webHostEnvironment.WebRootPath;
            Namespace = configuration["AppConfiguration:Namespace"];
            _appTableInfoRepository = appTableInfoRepository;
        }

        /// <summary>
        /// 获取模板根地址
        /// </summary>
        /// <returns></returns>
        public string GetTemplateRootPath() => TemplateRootPath;
        /// <summary>
        /// 获取代码生成根地址
        /// </summary>
        /// <returns></returns>
        public string GetCodesRootPath() => CodesRootPath;
        /// <summary>
        /// 获取代码文件压缩文件根地址
        /// </summary>
        /// <returns></returns>
        public string GetZipRootPath() => ZipRootPath;

        /// <summary>
        /// 代码创建时初始化 表数据
        /// </summary>
        /// <returns></returns>
        public async Task InitializationAsync()
            => _appTableInfos = await this._appTableInfoRepository.FindAppTableInfosAsync();

        /// <summary>
        /// 查询所有表信息
        /// </summary>
        /// <returns></returns>
        public List<AppTableInfo> FindAppTableInfos() => _appTableInfos;

        /// <summary>
        /// 查询所有表名称
        /// </summary>
        /// <returns></returns>
        public List<string> FindTableNames()
            => _appTableInfos.Select(w => w.TabName).Distinct().ToList();

        /// <summary>
        /// 根据表名查询所属字段
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public List<AppTableInfo> FindAppTableInfosByTableName(string tableName)
            => _appTableInfos.Where(w => w.TabName == tableName).ToList();

        /// <summary>
        /// 清除多余符号
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        private string ClearSymbol(StringBuilder code)
        {
            return code
                    .ToString()
                    .Replace("<pre>", "")
                    .Replace("</pre>", "")
                    .Trim()
                ;
        }

        /// <summary>
        /// 创建 Model 代码
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateModelByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/Model.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }
        /// <summary>
        /// Repository
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateRepositoryByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/Repository.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }

        /// <summary>
        /// Service
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateServiceByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/Service.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }
        /// <summary>
        /// Client Service
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateClientServiceByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/ClientService.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }

        /// <summary>
        /// Controller
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateControllerByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/Controller.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }

        /// <summary>
        /// Index
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateClientIndexByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/Index.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }
        /// <summary>
        /// Info
        /// </summary>
        /// <returns></returns>
        private async Task<string> CreateClientInfoByTableNameAsync(string tableName)
        {
            var path = $"{TemplateRootPath}/Info.cshtml";
            var appTableInfos = _appTableInfos.Where(w => w.TabName == tableName).ToList();
            var codeGenerationModel = new CodeGenerationModel(tableName, Namespace, appTableInfos);
            var codeString = await this._razorViewRender.RenderAsync(path, codeGenerationModel);
            return ClearSymbol(codeString);
        }

        /// <summary>
        /// 获取代码
        /// </summary>
        /// <param name="type"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public async Task<string> FindCodeByTypeAndTableNameAsync(string type, string tableName)
        {
            return type switch
            {
                "HZY.Models" => await this.CreateModelByTableNameAsync(tableName),
                //"HZY.Repository.DbSet" => await this.CreateRepositoryDbSetAsync(),
                "HZY.Repository" => await this.CreateRepositoryByTableNameAsync(tableName),
                "HZY.Services" => await this.CreateServiceByTableNameAsync(tableName),
                "HZY.Controller" => await this.CreateControllerByTableNameAsync(tableName),
                "HZY.Admin.Client.Index.Vue" => await this.CreateClientIndexByTableNameAsync(tableName),
                "HZY.Admin.Client.Info.Vue" => await this.CreateClientInfoByTableNameAsync(tableName),
                "HZY.Admin.Client.Service.js" => await this.CreateClientServiceByTableNameAsync(tableName),
                _ => string.Empty
            };
        }

        /// <summary>
        /// 获取代码文件名称
        /// </summary>
        /// <param name="type"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        private string FindCodeFileClassName(string type, string tableName)
        {
            return type switch
            {
                "HZY.Models" => $"{tableName}.cs",
                // "HZY.Repository.DbSet" => ,
                "HZY.Repository" => $"{tableName}Repository.cs",
                "HZY.Services" => $"{tableName}Service.cs",
                "HZY.Controller" => $"{tableName}Controller.cs",
                "HZY.Admin.Client.Index.Vue" => $"index.vue",
                "HZY.Admin.Client.Info.Vue" => $"info.vue",
                "HZY.Admin.Client.Service.js" => $"{tableName.FirstCharToLower()}Service.js",
                _ => string.Empty
            };
        }

        /// <summary>
        /// 获取下载代码信息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="tableName"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public (byte[] codeBytes, string className, string contentType) Download(string type, string tableName,
            string code)
        {
            var className = this.FindCodeFileClassName(type, tableName);

            var contentType = Tools.GetFileContentType[".cs"];
            if (className == "Index.Vue" || className == "Info.Vue")
            {
                contentType = Tools.GetFileContentType[".txt"];
            }

            return (Encoding.UTF8.GetBytes(code), className, contentType);
        }

        /// <summary>
        /// 创建代码文件
        /// </summary>
        /// <param name="type"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        private async Task<string> CreateCodeFilesAsync(string type, string tableName)
        {
            var path = $"{this._webRootPath}{CodesRootPath}";

            if (type == "HZY.Admin.Client.Index.Vue" || type == "HZY.Admin.Client.Info.Vue")
            {
                path += $"/Views";
                if (!Directory.Exists(path)) Directory.CreateDirectory(path);
                path += $"/{tableName.FirstCharToLower()}";
                if (!Directory.Exists(path)) Directory.CreateDirectory(path);
                //Index
                var codeString = await this.CreateClientIndexByTableNameAsync(tableName);
                await File.WriteAllTextAsync($"{path}/index.vue", codeString, Encoding.UTF8);
                //Info
                codeString = await this.CreateClientInfoByTableNameAsync(tableName);
                await File.WriteAllTextAsync($"{path}/info.vue", codeString, Encoding.UTF8);
                return path;
            }

            //
            path = $"{this._webRootPath}{CodesRootPath}/{type}";
            var className = this.FindCodeFileClassName(type, tableName);
            var code = await this.FindCodeByTypeAndTableNameAsync(type, tableName);
            //
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
            await File.WriteAllTextAsync($"{path}/{className}", code, Encoding.UTF8);
            return path;
        }

        /// <summary>
        /// 创建所有代码文件
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public async Task<bool> CreateAllCodeFilesAsync(string type)
        {
            var tableNames = this.FindTableNames();

            foreach (var item in tableNames)
            {
                await this.CreateCodeFilesAsync(type, item);
                await Task.Delay(50);
            }

            return true;
        }

        /// <summary>
        /// 创建数据库字典文件
        /// </summary>
        /// <returns></returns>
        public (byte[] excel, string dataBase) CreateDataDictionary()
        {
            var tables = this.FindTableNames();
            var workbook = new HSSFWorkbook();
            var dataBaseName = _appTableInfoRepository.Orm.Ado.ConnectionString.Split(';')
                .Where(w => w.ToLower().Trim().Contains("database"))
                .FirstOrDefault()?.Split('=')[1]
                ;

            foreach (var item in tables)
            {
                var tableInfos = this.FindAppTableInfosByTableName(item);
                var tableInfoFirst = tableInfos.FirstOrDefault();
                var tableRemark = tableInfoFirst.TabNameRemark;
                var sheet = workbook.CreateSheet(item + (string.IsNullOrWhiteSpace(tableRemark) ? "" : "_" + tableRemark));

                var i = 0;

                #region 配置表头

                var rowTitle = sheet.CreateRow(i);
                rowTitle.CreateCell(0).SetCellValue("表空间");
                sheet.SetColumnWidth(0, 20 * 256);
                rowTitle.CreateCell(1).SetCellValue("表名");
                sheet.SetColumnWidth(1, 20 * 256);
                rowTitle.CreateCell(2).SetCellValue("表描述");
                sheet.SetColumnWidth(2, 20 * 256);
                rowTitle.CreateCell(3).SetCellValue("字段");
                sheet.SetColumnWidth(3, 20 * 256);
                rowTitle.CreateCell(4).SetCellValue("字段描述");
                sheet.SetColumnWidth(4, 20 * 256);
                rowTitle.CreateCell(5).SetCellValue("是否主键");
                sheet.SetColumnWidth(5, 20 * 256);
                rowTitle.CreateCell(6).SetCellValue("是否自增");
                sheet.SetColumnWidth(6, 20 * 256);
                rowTitle.CreateCell(7).SetCellValue("可否为 Null");
                sheet.SetColumnWidth(7, 20 * 256);
                rowTitle.CreateCell(8).SetCellValue("数据库类型");
                sheet.SetColumnWidth(8, 20 * 256);
                rowTitle.CreateCell(9).SetCellValue("C#类型");
                sheet.SetColumnWidth(9, 20 * 256);
                rowTitle.CreateCell(10).SetCellValue("数据长度");
                sheet.SetColumnWidth(10, 20 * 256);

                #endregion

                foreach (var tableInfo in tableInfos)
                {
                    i++;
                    var index = tableInfos.IndexOf(tableInfo);
                    var row = sheet.CreateRow(i);
                    row.CreateCell(0).SetCellValue(tableInfo.Namespace);
                    row.CreateCell(1).SetCellValue(tableInfo.TabName);
                    row.CreateCell(2).SetCellValue(tableInfo.TabNameRemark);
                    row.CreateCell(3).SetCellValue(tableInfo.ColName);
                    row.CreateCell(4).SetCellValue(tableInfo.ColRemark);
                    row.CreateCell(5).SetCellValue(tableInfo.ColIsKey == 1 ? "是" : "否");
                    row.CreateCell(6).SetCellValue(tableInfo.ColIsIdentity == 1 ? "是" : "否");
                    row.CreateCell(7).SetCellValue(tableInfo.ColIsNull == 1 ? "是" : "否");
                    row.CreateCell(8).SetCellValue(tableInfo.ColType);
                    row.CreateCell(9).SetCellValue(tableInfo.CsType);
                    row.CreateCell(10).SetCellValue(tableInfo.ColMaxLength);
                }

            }

            //填充byte
            using var ms = new MemoryStream();
            workbook.Write(ms);
            return (ms.ToArray(), dataBaseName);
        }









    }
}